package com.zoe.thread.th03_线程通信;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author Zoe
 * @Date: 2021/05/01
 * @Description 现在2个线程，可以操作初始值为0的一个变量，
 * 实现一个线程对变量+1，一个线程对该变量-1，
 * 实现交替，来10轮，变量初始值为0；
 *
 * 1: 高内聚低耦合的前提下/线程操作资源类
 * 2: 口诀：判断/干活/通知
 * 3: 多线程交互中,必须要防止多线程的虚假唤醒，也即（判断只用while 不能用if）
 *
 * 生产 消费
 */

class Cake2 {
    private int number = 0;

    private int incre = 0;
    private int decre = 0;


    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    public void increment() {
        lock.lock();
        try {
            // 1: 判断
            while (number != 0) {
                // wait();
                condition.await();
            }

            // 2: 业务逻辑
            number++;
            incre++;

            // 3: 通知
            // notifyAll();
            condition.signalAll();
            System.out.println(incre + "  " + Thread.currentThread().getName() + " 生产了蛋糕" + number);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            // 操作资源类方法
            while (number == 0) {
                // wait();
                condition.await();
            }
            number--;
            decre++;
            // notifyAll();
            condition.signalAll();
            System.out.println(decre + "  " + Thread.currentThread().getName() + " 消费了蛋糕" + number);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

public class ThreadWaitNotifyDemoLock {
    public static void main(String[] args) {
        Cake2 cake2 = new Cake2();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                cake2.increment();
            }
        }, "厨师A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                cake2.increment();
            }
        }, "厨师B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                cake2.decrement();
            }
        }, "消费A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                cake2.decrement();
            }
        }, "消费B").start();
    }
}
